/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦，本文采用木兰宽松许可证第2版]
 * 
 * https://zhiqim.org/project/zhiqim_kit/zhiqim_git.htm
 *
 * ZhiqimGit is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.git.command;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.zhiqim.git.Git;
import org.zhiqim.git.GitCommand;
import org.zhiqim.git.GitWalker;
import org.zhiqim.git.objer.objectid.RevCommit;
import org.zhiqim.git.refer.Ref;
import org.zhiqim.git.refer.RefComparator;


/**
 * 分枝查询列表命令
 * http://www.kernel.org/pub/software/scm/git/docs/git-branch.html
 *
 * @version v1.0.0 @author zhichenggang 2017-3-12 新建与整理
 */
public class BranchListCommand extends GitCommand<List<Ref>>
{
    /** 查询方式，-a(local&remote), -r(仅remote) */
    public enum ListMode {ALL, REMOTE;}
    
    private ListMode listMode;
    private String containsCommit;

    public BranchListCommand(Git git)
    {
        super(git);
    }
    
    /******************************************************************************/
    //设置参数
    /******************************************************************************/
    
    /** 设置查询方式 */
    public BranchListCommand setListMode(ListMode listMode)
    {
        this.listMode = listMode;
        return this;
    }

    /** 设置包含指定的提交编号 */
    public BranchListCommand setContains(String containsCommit)
    {
        this.containsCommit = containsCommit;
        return this;
    }
    
    /******************************************************************************/
    //预处理&执行
    /******************************************************************************/

    protected List<Ref> execute() throws Exception
    {
        List<Ref> refs = new ArrayList<Ref>();

        if (listMode == null)
        {//默认取本身的
            refs.addAll(getRefs(P_REFS_HEADS_));
        }
        else if (listMode == ListMode.REMOTE)
        {//指定取远程的
            refs.addAll(getRefs(P_REFS_REMOTES_));
        }
        else
        {//两者都取
            refs.addAll(getRefs(P_REFS_HEADS_));
            refs.addAll(getRefs(P_REFS_REMOTES_));
        }

        //过滤并排序
        return RefComparator.sort(filterRefs(refs));
    }

    /******************************************************************************/
    // 私有方法
    /******************************************************************************/

    private List<Ref> getRefs(String prefix) throws IOException
    {
        return git.getRefer().getRefList(prefix);
    }
    
    private List<Ref> filterRefs(List<Ref> refs) throws IOException
    {
        if (containsCommit == null)
        {//未要求包含提交的，HEAD写加入
            Ref head = git.findRef(HEAD);
            if (head != null && head.getUltimateTarget().getName().equals(HEAD))
                refs.add(head);
            
            return refs;
        }
        
        RevCommit commit = git.resolve(containsCommit, RevCommit.class);
        if (commit == null)
            throw new IOException("该引用不存在："+containsCommit);

        List<Ref> result = new ArrayList<Ref>();
        GitWalker walker = new GitWalker(git);
        
        for (Ref ref : refs)
        {
            RevCommit headCommit = walker.parseCommit(ref.getObjectId());
            if (headCommit.getCommitTime() < commit.getCommitTime())
            {//分枝时间小于提交时间的跳过
                continue;
            }
            
            if (walker.isFastward(commit, headCommit))
            {//分枝是提交的子提交的加入
                result.add(ref);
            }
        }
        return result;
    }
}
